package cn.lyjuan.payment.third.base.model.pay.domain;

import cn.lyjuan.base.exception.util.ErrUtils;
import cn.lyjuan.base.util.HttpUtils;
import cn.lyjuan.base.util.JsonUtils;
import cn.lyjuan.base.util.RandomUtils;
import cn.lyjuan.base.util.SpringUtils;
import cn.lyjuan.payment.third.base.common.cst.StateConst;
import cn.lyjuan.payment.third.base.common.entity.pay.*;
import cn.lyjuan.payment.third.base.common.enums.impl.*;
import cn.lyjuan.payment.third.base.common.mapper.*;
import cn.lyjuan.payment.third.base.model.app.check.AppCheck;
import cn.lyjuan.payment.third.base.model.app.domain.AppModel;
import cn.lyjuan.payment.third.base.model.cst.PayPropeties;
import cn.lyjuan.payment.third.base.model.exception.ErrCodeImpl;
import cn.lyjuan.payment.third.base.model.pay.mapper.IPayTranMapper;
import cn.lyjuan.payment.third.base.model.pay.vo.NotifyResVo;
import cn.lyjuan.payment.third.base.pay.chl.IPayChl;
import cn.lyjuan.payment.third.base.pay.chl.impl.ali.bean.AlipayTransferReq;
import cn.lyjuan.payment.third.base.pay.chl.impl.iap.bean.IapQueryRes;
import cn.lyjuan.payment.third.base.pay.chl.impl.iap.bean.LatestReceiptInfoVo;
import cn.lyjuan.payment.third.base.pay.chl.impl.iap.util.IapSubmit;
import cn.lyjuan.payment.third.base.pay.enums.IosNotifyTypeEnum;
import cn.lyjuan.payment.third.base.pay.enums.RefundEnum;
import cn.lyjuan.payment.third.base.pay.enums.SimpleChlEnum;
import cn.lyjuan.payment.third.base.pay.enums.SimpleStatusEnum;
import cn.lyjuan.payment.third.base.pay.vo.req.*;
import cn.lyjuan.payment.third.base.pay.vo.res.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 交易信息
 */
@Slf4j
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class PayModel {
    /**
     * 通知和回调URL中的流水号占位符
     */
    private static final String URL_LOCAL_NO_REP = "#LOCAL_NO#";
    @Resource
    private PayPropeties payPropeties;
    @Resource
    private PayTranEntityMapper mapper;
    @Resource
    private PayTransferEntityMapper payTransferEntityMapper;
    @Resource
    private PayNotifyEntityMapper notifyMapper;
    @Resource
    private PayIapEntityMapper iapEntityMapper;
    @Resource
    private PayRefundEntityMapper refundEntityMapper;
    @Resource
    private PayRefundMapper payRefundMapper;
    @Resource
    private IPayTranMapper tranMapper;

    private PayTranEntity entity;

    public boolean query(String localNo) {
        this.entity = tranMapper.findByLocalNo(localNo);

        return null != this.entity;
    }

    /**
     * 查询pay-third订单
     *
     * @param localNo 订单
     * @return PayTranEntity
     */
    public PayTranEntity queryTran(String localNo) {
        return tranMapper.findByLocalNo(localNo);
    }

    /**
     * 根据交易id查询数据
     *
     * @param tranId 交易id
     * @return PayIapEntity
     */
    public PayIapEntity queryIap(Long tranId) {
        return iapEntityMapper.queryByTranId(tranId);
    }

    /**
     * 支付
     *
     * @param appId
     * @param chl
     * @param appTranNo
     * @param goods
     * @param flag
     * @param amt          交易金额，分
     * @param appNotifyUrl
     * @param appReturnUrl
     * @param params       第三方支付平台的独立参数
     * @return 支付平台支付需要的信息
     */
    //@Transactional(rollbackFor = Throwable.class)
    public PayRes pay(IPayChl chl, ChlCnf cnf, Integer appId, Integer chlId, ChlEnum chlEnum, String appTranNo,
                      String goods, String flag, Integer amt,
                      String appNotifyUrl, String appReturnUrl,
                      PayReq.IPayReq params) {
        // 封装 chl 参数
        BaseRes check = chl.checkPayParams(params);
        if (!check.isSucc()) {
            ErrUtils.appThrow(ErrCodeImpl.PAY_PARAMS_INVALID, check.getMsg());
        }
        String localTranNo = RandomUtils.uuid();
        // 通知地址
        String localNotifyUrl;
        // 回调地址
        String localReturnUrl;
        if (chlEnum.equals(ChlEnum.IAP)) {
            localReturnUrl = payPropeties.getIosReturnUrl();
            localNotifyUrl = payPropeties.getNotifyUrl();
        } else {
            localNotifyUrl = notifyUrl(localTranNo);
            localReturnUrl = returnUrl(localTranNo);
        }

        // 先入库
        addTran(appId, chlId, chlEnum, appTranNo, localTranNo, goods, flag,
                amt, appNotifyUrl, appReturnUrl, localNotifyUrl, localReturnUrl, 3);

        PayReq req = new PayReq(localTranNo, goods, amt, localNotifyUrl, localReturnUrl, params);

        // chl创建交易信息
        PayRes res = chl.order(req, cnf);
        res.setLocalNo(localTranNo);
        if (!res.isSucc()) {
            ErrUtils.appThrow(ErrCodeImpl.PAY_ORDER_FAILED, res.getMsg());
        }
        // 返回交易信息
        return res;
    }

    /**
     * 支付
     *
     * @param appId     appId
     * @param chl       chl
     * @param appTranNo appTranNo
     * @param title     title
     * @param identity  身份
     * @param chlEnum   chlEnum
     * @param chlId     chlId
     * @param cnf       cnf
     * @param flag      flag
     * @param remark    备注
     * @param amt       交易金额，分
     * @param params    第三方支付平台的独立参数
     * @return 支付平台支付需要的信息
     */
    //@Transactional(rollbackFor = Throwable.class)
    public TransferRes transfer(IPayChl chl, ChlCnf cnf, Integer appId, Integer chlId, ChlEnum chlEnum,
                                String appTranNo, String title, String identity, String realName, String remark,
                                String flag, Integer amt, TransferReq.ITransferReq params
    ) {
        // 封装 chl 参数
        BaseRes check = chl.checkTransferParams(params);
        if (!check.isSucc()) {
            ErrUtils.appThrow(ErrCodeImpl.TRANSFER_PARAMS_INVALID, check.getMsg());
        }
        String localTranNo = RandomUtils.uuid();

        // 找到旧的订单
        Example ex = new Example(PayTransferEntity.class);
        ex.setOrderByClause("id desc limit 1");
        ex.createCriteria().andEqualTo("appNo", appTranNo);
        PayTransferEntity entity = payTransferEntityMapper.selectOneByExample(ex);
        if (entity != null) {
            identity = entity.getIdentity();
            title = entity.getTitle();
            amt = entity.getAmount();
        } else {
            // 先入库 - 并发 依赖于 数据库 唯一索引
            entity = addTransfer(appId, chlId, chlEnum, appTranNo, localTranNo, identity, realName, title, flag, amt, 3);
        }

        // 断言 插入数据成功
        if (entity.getId() == null) {
            ErrUtils.appThrow(ErrCodeImpl.TRANSFER_FAIL, "data error");
        }
        TransferReq<AlipayTransferReq> req = new TransferReq(localTranNo, title, amt, remark, identity, params);

        // chl创建转账信息
        TransferRes res = chl.transfer(req, cnf);
        if (!res.isSucc()) {
            // todo: maybe need query last time
            //saveTransfer(entity, TransferStatusEnum.FAIL);
            ErrUtils.appThrow(ErrCodeImpl.TRANSFER_FAIL, res.getMsg());
        }
        res.setLocalNo(localTranNo);
        // update
        saveTransfer(entity, TransferStatusEnum.SUCC);
        // 返回交易信息
        return res;
    }

    /**
     * 处理ios回调
     *
     * @param tmpEnum       tmpEnum
     * @param data          data
     * @param iapData       iapData
     * @param payTranEntity payTranEntity
     */
    @Transactional(rollbackFor = Exception.class)
    public void handleIosNotify(IosNotifyTypeEnum tmpEnum, List<LatestReceiptInfoVo> data, PayIapEntity iapData, PayTranEntity payTranEntity) {
        // 直接插数据
        handleIapHistoryListData(data, payTranEntity.getLocalNo(), payTranEntity.getAppNo());
        // 拿到最后一条数据
        LatestReceiptInfoVo latestData = data.get(data.size() - 1);
        // 拿到倒数第二条
        LatestReceiptInfoVo latestData2 = data.get(data.size() - 2);
        // 退款
        if (tmpEnum.equals(IosNotifyTypeEnum.REFUND)) {
            PayTranEntity updateData = new PayTranEntity();
            updateData.setId(payTranEntity.getId());
            updateData.setThirdNo(latestData.getTransaction_id());
            updateData.setStatus(PayStatusEnum.FAIL);
            if (latestData.getCancellation_date() != null) {
                updateData.setEndTime(IapSubmit.convertStringToISO8601Date(latestData.getCancellation_date()));
            }
        }
        // 初始化购买
        else if (tmpEnum.equals(IosNotifyTypeEnum.INITIAL_BUY)) {
            //
        }
        // 取消
        else if (tmpEnum.equals(IosNotifyTypeEnum.CANCEL)) {
            //
        }
    }

    /**
     * 处理历史数据
     *
     * @param data    data
     * @param localNo localNo
     * @param appNo   appNo
     */
    public void handleIapHistoryListData(List<LatestReceiptInfoVo> data, String localNo, String appNo) {
        if (data.size() == 1) {
            return;
        }
        // Because it is a callback, the verification is all passed   ->    IapStatusEnum.OK    ->   IapRefundTypeEnum.NO  wait for update
        for (int i = 1; i < data.size(); i++) {
            if (data.get(i) != null) {
                try {
                    insertPayIap(data.get(i), appNo, localNo, IapStatusEnum.OK, IapRefundTypeEnum.NO);
                } catch (Throwable e) {
                    // inhibit Exception [insert mysql]
                }
            }
        }
    }

    /**
     * 入库
     *
     * @param appId
     * @param chlId
     * @param chlEnum
     * @param appTranNo
     * @param goods
     * @param flag
     * @param amt
     * @param appNotifyUrl
     * @param appReturnUrl
     * @param localNotifyUrl
     * @param localReturnUrl
     * @return
     */
    private void addTran(Integer appId, Integer chlId, ChlEnum chlEnum, String appTranNo, String localTranNo,
                         String goods, String flag, Integer amt, String appNotifyUrl, String appReturnUrl,
                         String localNotifyUrl, String localReturnUrl, int tryCount) {
        // 入库
        PayTranEntity tmp = new PayTranEntity();
        tmp.setAppId(appId);
        tmp.setChlId(chlId);
        tmp.setChlType(chlEnum);
        tmp.setGoods(goods);
        tmp.setAppNo(appTranNo);
        tmp.setLocalNo(localTranNo);
        tmp.setAmount(amt);
        tmp.setFlag(flag);
        tmp.setAppNotifyUrl(appNotifyUrl);
        tmp.setAppReturnUrl(appReturnUrl);
        tmp.setNotifyUrl(localNotifyUrl);
        tmp.setReturnUrl(localReturnUrl);
        tmp.setStatus(PayStatusEnum.UN_PAY);
        // 不再保存，无意义
//        if (null != res.getParams())
//            tmp.setThirdParams(JsonUtils.to(res.getParams()));
        tmp.setSversion(0);
        tmp.setUpdatetime(LocalDateTime.now());
        tmp.setCreatetime(tmp.getUpdatetime());

        try {
            this.mapper.insertSelective(tmp);
        } catch (Throwable t1) {
            if (--tryCount > 0) {
                addTran(appId, chlId, chlEnum, appTranNo, localTranNo, goods, flag,
                        amt, appNotifyUrl, appReturnUrl, localNotifyUrl, localReturnUrl, tryCount);
            } else {
                ErrUtils.appThrow(ErrCodeImpl.ERR, "pay order error", t1);
            }
        }
    }

    /**
     * 入库
     *
     * @param appId       appId
     * @param chlId       chlId
     * @param chlEnum     chlEnum
     * @param appTranNo   appTranNo
     * @param identity    identity
     * @param realName    realName
     * @param title       title
     * @param localTranNo localTranNo
     * @param tryCount    tryCount
     * @param flag        flag
     * @param amt         amt
     */
    private PayTransferEntity addTransfer(Integer appId, Integer chlId, ChlEnum chlEnum, String appTranNo, String localTranNo,
                                          String identity, String realName, String title, String flag, Integer amt, int tryCount) {
        // 入库
        PayTransferEntity tmp = new PayTransferEntity();
        tmp.setAppId(appId);
        tmp.setChlId(chlId);
        tmp.setChlType(chlEnum);
        tmp.setIdentity(identity);
        tmp.setRealName(realName);
        tmp.setTitle(title);
        tmp.setAppNo(appTranNo);
        tmp.setLocalNo(localTranNo);
        tmp.setAmount(amt);
        tmp.setFlag(flag);
        tmp.setStatus(TransferStatusEnum.UN_TRANSFER);
        // 不再保存，无意义
//        if (null != res.getParams())
//            tmp.setThirdParams(JsonUtils.to(res.getParams()));
        tmp.setUpdatetime(LocalDateTime.now());
        tmp.setCreatetime(tmp.getUpdatetime());

        try {
            this.payTransferEntityMapper.insertSelective(tmp);
        } catch (Throwable t1) {
            if (--tryCount > 0) {
                addTransfer(appId, chlId, chlEnum, appTranNo, localTranNo, identity, realName, title, flag, amt, tryCount);
            } else {
                ErrUtils.appThrow(ErrCodeImpl.ERR, "pay order error", t1);
            }
        }
        return tmp;
    }

    /**
     * 更新操作结果
     *
     * @param entity  entity
     * @param tmpEnum tmpEnum
     */
    private void saveTransfer(PayTransferEntity entity, TransferStatusEnum tmpEnum) {
        PayTransferEntity entity1 = new PayTransferEntity();
        entity1.setId(entity.getId());
        entity1.setStatus(TransferStatusEnum.SUCC);
        entity1.setEndTime(LocalDateTime.now());
        this.payTransferEntityMapper.updateByPrimaryKeySelective(entity1);
    }

    /**
     * 生成通知地址
     *
     * @param localNo
     * @return
     */
    private String notifyUrl(String localNo) {
        return payPropeties.getNotifyUrl().replaceAll(URL_LOCAL_NO_REP, localNo);
    }

    /**
     * 生成回调页面
     *
     * @param localNo
     * @return
     */
    private String returnUrl(String localNo) {
        return payPropeties.getReturnUrl().replaceAll(URL_LOCAL_NO_REP, localNo);
    }

    /**
     * 支付结果异步通知
     * todo 在更新交易数据时，与查询加锁防止多次更新
     *
     * @return
     */
    public NotifyResVo notifyResult(AppModel app, IPayChl chl, ChlCnf cnf) {
        // 通知参数
        // 每个支付平台获取通知参数的方式不一致，所有直接传递request
        HttpServletRequest req = SpringUtils.getRequest();
        NotifyReq.INotifyReq params = chl.parseNotifyParams(req);
        NotifyReq notifyReq = new NotifyReq(this.entity.getAppNo(), params);
        // 处理通知
        NotifyRes res = chl.notifyStatus(notifyReq, cnf);

        if (!res.isSucc()) {
            ErrUtils.appThrow(ErrCodeImpl.PAY_NOTIFY_FAILED, res.getMsg());
        }
        if (this.entity.getStatus().name().equals(res.getStatus().name())) {
            return new NotifyResVo(PayStatusEnum.from(res.getStatus()), res.getResMsg());
        }
        // 入库
        saveStatus(app, res.getStatus(), res.getTranNo());


        return new NotifyResVo(PayStatusEnum.from(res.getStatus()), res.getResMsg());
    }

    /**
     * 查询交易状态
     * todo 平台需要主动调用查询功能更新交易状态，不能依赖通知
     *
     * @param chl
     * @param cnf
     * @param params
     * @return
     */
    @Transactional(rollbackFor = Throwable.class)
    public PayStatusEnum queryResult(AppModel app, IPayChl chl, ChlCnf cnf, Map<String, String> params) {
        // 如果交易状态已发生更改
        if (PayStatusEnum.UN_PAY != this.entity.getStatus()) {
            return this.entity.getStatus();
        }

        // 解析支付平台参数
        QueryReq.IQueryReq queryParams = chl.parseQueryParams(params);
        QueryReq req = new QueryReq(this.entity.getLocalNo(), null, queryParams);

        // 查询交易状态
        QueryRes res = chl.queryStatus(req, cnf);

        if (!res.isSucc()) {
            ErrUtils.appThrow(ErrCodeImpl.PAY_QUERY_FAILED, res.getMsg());
        }
        // handle iap bind transactionId
        if (chl.chl().equals(SimpleChlEnum.IAP)) {
            LatestReceiptInfoVo data = ((IapQueryRes) res.getParams()).getData();
            int iapNum = insertPayIap(data, this.entity.getAppNo(), this.entity.getLocalNo(), IapStatusEnum.OK, IapRefundTypeEnum.NO);
            if (iapNum <= 0) {
                ErrUtils.appThrow(ErrCodeImpl.PAY_IAP_RECEIPT_ALREADY_USE, res.getMsg());
            }
            this.entity.setAppNotifyUrl("");
        }
        // 更新数据
        saveStatus(app, res.getStatus(), res.getTranNo());
        return this.entity.getStatus();
    }

    /**
     * 更新交易状态
     * todo 目前仅用乐观锁保证同步
     *
     * @param status
     * @param tranNo
     */
    private void saveStatus(AppModel app, SimpleStatusEnum status, String tranNo) {
        // 更新数据
        if (SimpleStatusEnum.UNKNOWN == status)// 未知状态
        {
            return;
        }

        if (SimpleStatusEnum.SUCC == status) {
            this.entity.setStatus(PayStatusEnum.SUCC);
        } else if (SimpleStatusEnum.FAIL == status) {
            this.entity.setStatus(PayStatusEnum.FAIL);
        }

        this.entity.setEndTime(LocalDateTime.now());
        this.entity.setThirdNo(tranNo);

        Example ex = new Example(PayTranEntity.class);
        ex.createCriteria()
                .andEqualTo("sversion", this.entity.getSversion())
                .andEqualTo("id", this.entity.getId());

        this.entity.setSversion(this.entity.getSversion() + 1);
        int count = this.mapper.updateByExampleSelective(this.entity, ex);

        if (count < 1)// 未保存成功
        {
            ErrUtils.appThrow(ErrCodeImpl.PAY_DATA_CHANGED);
        }

        // 新增通知信息
        addNotify(app);
    }

    /**
     * 新增通知信息
     */
    private void addNotify(AppModel app) {
        PayNotifyEntity pne = new PayNotifyEntity();
        pne.setId(this.entity.getId());
        pne.setUrl(this.entity.getAppNotifyUrl());
        pne.setCount(0);
        pne.setNexttime(LocalDateTime.now());
        pne.setStatus(StateConst.NO_BL);
        pne.setCreatetime(pne.getNexttime());

        Map<String, String> paramsMap = new HashMap<>();
        paramsMap.put("appId", Integer.toString(this.entity.getAppId()));
        paramsMap.put("appNo", this.entity.getAppNo());
        paramsMap.put("status", this.entity.getStatus().name());
//        params.put("time", this.entity.getEndTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        String sign = AppCheck.sign(paramsMap, app.getEntity().getKeyMd5());
        paramsMap.put("sign", sign);

        String params = HttpUtils.paraToForm(paramsMap);
        pne.setParams(params);

        this.notifyMapper.insert(pne);
    }

    private Integer addRefund(
            String appRefundOrderNo
            , String selfRefundOrderNo
            , Integer amt
    ) {
        PayRefundEntity payRefundEntity = new PayRefundEntity();
        payRefundEntity.setTranId(this.entity.getId());
        payRefundEntity.setAppNo(this.entity.getLocalNo());
        payRefundEntity.setAppRefundNo(appRefundOrderNo);
        payRefundEntity.setPayRefundNo(selfRefundOrderNo);
        payRefundEntity.setAmount(amt.toString());
        payRefundEntity.setStatus(RefundEnum.UNKNOWN.getCode());
        payRefundEntity.setCreatetime(LocalDateTime.now());
        refundEntityMapper.insertSelective(payRefundEntity);
        return payRefundEntity.getId();
    }

    private void updateRefundAndUpdatePayTran(
            Integer refundId,
            String outRefundOrderNo,
            @Nullable Double rate,
            Integer amt,
            RefundRes res
    ) {
        // 插入退款记录
        PayRefundEntity payRefundEntity = new PayRefundEntity();
        payRefundEntity.setId(refundId);
        payRefundEntity.setThirdRefundNo(outRefundOrderNo);
        if (res.getStatus() != SimpleStatusEnum.SUCC) {
            payRefundEntity.setStatus(RefundEnum.FAIL.getCode());
        } else {
            payRefundEntity.setStatus(RefundEnum.SUCC.getCode());
        }
        refundEntityMapper.updateByPrimaryKeySelective(payRefundEntity);
        // 保留旧的费率
        if (this.entity.getTranFee() != null) {
            rate = null;
        }
        // 更新支付订单 退款数据
        mapper.updateRefundAmountLimitMax(this.entity.getId(), amt, rate);
    }

    /**
     * 对原交易进行退款
     *
     * @param app app
     * @param chl chl
     * @param cnf cnf
     * @return boolean
     */
    @Transactional(rollbackFor = Throwable.class)
    public boolean orderRefund(AppModel app, IPayChl chl, ChlCnf cnf, @Nullable Double rate, Integer amt, String appRefundNo) {
        // 如果交易状态已发生更改
        if (PayStatusEnum.SUCC != this.entity.getStatus()) {
            return false;
        }
        // 退款金额 > (总价 - 已退款金额)
        if (amt > entity.getAmount() - entity.getRefundAmount()) {
            ErrUtils.appThrow(ErrCodeImpl.REFUND_AMOUNT_EXCEEDS_LIMIT, "退款金额超过限制");
        }
        // 尝试找到 尝试退款但未退成功的 selfRefundOrderNO
        PayRefundEntity oldNotSuccessSelfRefundO = payRefundMapper.selectNotRefundSuccessOrderNo(entity.getId(), appRefundNo, amt, entity.getLocalNo());
        Integer payRefundId = null;
        String localRefundAppNo = null;
        if (oldNotSuccessSelfRefundO == null) {
            // 生成 self refund order no
            localRefundAppNo = RandomUtils.uuid();
            // 生成记录
            payRefundId = addRefund(appRefundNo, localRefundAppNo, amt);
        } else {
            localRefundAppNo = oldNotSuccessSelfRefundO.getPayRefundNo();
            payRefundId = oldNotSuccessSelfRefundO.getId();
        }
        // exec or 查询交易状态
        RefundRes res = chl.orderRefund(localRefundAppNo, entity.getLocalNo(), entity.getAmount(), amt, cnf);
        if (res.getStatus() != SimpleStatusEnum.SUCC) {
            log.error("Order refund failed, tranId:{}, appRefundNo:{}, chl:{} ==> result:{}", entity.getId(), appRefundNo, chl.chl(), JsonUtils.to(res));
            ErrUtils.appThrow(ErrCodeImpl.PAY_REFUND_FAILED, res.getMsg());
        }
        // 更新退款记录 || 更新订单
        updateRefundAndUpdatePayTran(payRefundId, res.getTranNo(), rate, amt, res);
        return true;
    }

    /**
     * 插入pay_iap绑定表数据
     *
     * @param param   参数
     * @param appNo   appNo
     * @param localNo localNo
     * @return int
     */
    @Transactional(rollbackFor = Exception.class)
    public int insertPayIap(LatestReceiptInfoVo param, String appNo, String localNo, IapStatusEnum iapStatusEnum, IapRefundTypeEnum iapRefundTypeEnum) {
        Example ex = new Example(PayIapEntity.class);
        ex.setOrderByClause("id desc limit 1");
        ex.createCriteria().andEqualTo("tranId", Long.parseLong(param.getTransaction_id()));
        PayIapEntity old = iapEntityMapper.selectOneByExample(ex);
        if (old != null && old.getId() != null) {
            PayIapEntity data = new PayIapEntity();
            data.setId(old.getId());
            data.setAppNo(appNo);
            data.setLocalNo(localNo);
            data.setStatus(IapStatusEnum.OK);
            data.setType(IapRefundTypeEnum.NO);
            data.setVerifyTime(LocalDateTime.now());
            int res = iapEntityMapper.updateByPrimaryKeySelective(data);
            return res;
        }
        PayIapEntity data = new PayIapEntity();
        data.setTranId(Long.parseLong(param.getTransaction_id()));
        data.setOriginId(Long.parseLong(param.getOriginal_transaction_id()));
        data.setAppNo(appNo);
        data.setLocalNo(localNo);
        data.setStatus(iapStatusEnum);
        data.setType(iapRefundTypeEnum);
        LocalDateTime iapTime;
        if (iapRefundTypeEnum.equals(IapRefundTypeEnum.YES)) {
            iapTime = IapSubmit.convertStringToISO8601Date(param.getCancellation_date());
            data.setRefundTime(iapTime);
        } else {
            iapTime = IapSubmit.convertStringToISO8601Date(param.getPurchase_date());
            data.setVerifyTime(iapTime);
        }
        data.setCreateTime(iapTime);
        data.setVerifyTime(LocalDateTime.now());
        return iapEntityMapper.insertSelective(data);
    }

    public PayTranEntityMapper getMapper() {
        return mapper;
    }

    public void setMapper(PayTranEntityMapper mapper) {
        this.mapper = mapper;
    }

    public PayNotifyEntityMapper getNotifyMapper() {
        return notifyMapper;
    }

    public void setNotifyMapper(PayNotifyEntityMapper notifyMapper) {
        this.notifyMapper = notifyMapper;
    }

    public PayTranEntity getEntity() {
        return entity;
    }

    public void setEntity(PayTranEntity entity) {
        this.entity = entity;
    }
}
